package com.zjy.weather.view

import android.content.Context
import android.graphics.*
import android.util.AttributeSet
import android.view.View
import com.zjy.weather.util.UIUtils

/**
 * Created by zhongjy on 2017/11/6.
 * Copyright (C) 2017 zhongjy. All rights reserved.
 */
data class LineData(var title: String, var num: Float)

class LineView : View {


    var mContext: Context
    var mPadding: Int = UIUtils.dip2px(context, 15f)
    var mWidth: Int
    var mHeight: Int
    var mWidthDegree: Float
    var mWidthCount = 4
    var mData: List<LineData>? = null
    var suffix: String? = null

    var titlePaint: Paint
    var numPaint: Paint
    var linePaint: Paint
    var pointPaint: Paint
    var path: Path

    var perDegree = 0
    var xLength = 0
    var points: ArrayList<Point>//即将要穿越的点集合
    var midPoints: ArrayList<Point>// 中点集合
    var midMidPoints: ArrayList<Point>//中点的中点集合
    var controlPoints: ArrayList<Point>//移动后的点集合(控制点)


    init {
        mContext = context
        mWidth = UIUtils.screenWidth - mPadding * 2
        mHeight = (UIUtils.dip2px(context, 120f))
        mWidthDegree = ((mWidth - 2 * mPadding) / mWidthCount).toFloat()
        points = ArrayList()
        midPoints = ArrayList()
        midMidPoints = ArrayList()
        controlPoints = ArrayList()

        titlePaint = Paint()
        titlePaint.color = Color.GRAY
        titlePaint.isAntiAlias = true
        titlePaint.strokeWidth = 1f
        titlePaint.textSize = 30f
        titlePaint.textAlign = Paint.Align.CENTER

        numPaint = Paint()
        numPaint.color = Color.BLACK
        numPaint.isAntiAlias = true
        numPaint.strokeWidth = 1f
        numPaint.textSize = 30f
        numPaint.textAlign = Paint.Align.CENTER

        linePaint = Paint()
        linePaint.color = Color.BLACK
        linePaint.isAntiAlias = true
        linePaint.isDither = true
        linePaint.strokeWidth = 5f
        linePaint.style = Paint.Style.STROKE

        pointPaint = Paint()
        pointPaint.isAntiAlias = true
        pointPaint.strokeWidth = 4f

        path = Path()
    }

    constructor(context: Context) : super(context)

    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)

    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)

    fun setData(data: List<LineData>, prefix: String?) {
        mData = data
        this.suffix = prefix
        postInvalidate()
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        val widthSpecMode = View.MeasureSpec.getMode(widthMeasureSpec)
        val widthSpecSize = View.MeasureSpec.getSize(widthMeasureSpec)
        var width = 0
        if (widthSpecMode == MeasureSpec.AT_MOST) {
            width = widthSpecSize;
        } else if (widthSpecMode == MeasureSpec.EXACTLY) {
            width = widthSpecSize;
        }
        mWidth = widthSpecSize
        mWidthDegree = (mWidth - 2 * mPadding).toFloat() / mWidthCount
        setMeasuredDimension(width, mHeight)
    }

    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)
        canvas?.let {
            canvas.drawColor(Color.WHITE)
            mData?.let {
                drawTitle(canvas)
                dwawLine(canvas)
            }
        }
    }

    fun drawTitle(canvas: Canvas) {
        mData?.let {
            for (i in it.indices) {
                canvas.drawText(it.get(i).title, i * mWidthDegree + mPadding, (mHeight - 10).toFloat(), titlePaint)
                var title = it.get(i).num.toString()
                suffix?.let {
                    title = title + suffix
                }
                canvas.drawText(title, i * mWidthDegree + mPadding, (mHeight - 40).toFloat(), numPaint)
            }
        }
    }


    fun dwawLine(canvas: Canvas) {
        var degreeCount = 0
        var start = 0
        fun initPoint(data: List<LineData>) {
            points.clear()
            midPoints.clear()
            midMidPoints.clear()
            controlPoints.clear()

            for (i in data.indices) {
                var x = (i * mWidthDegree + mPadding).toInt()
                var num = degreeCount - data.get(i).num + start
                var y = (num * perDegree).toInt() + mPadding
                points.add(Point(x, y))
            }
            for (i in 0 until points.size - 1) {
                midPoints.add(Point((points[i].x + points[i + 1].x) / 2, (points[i].y + points[i + 1]
                        .y) / 2))
            }

            for (i in 0 until midPoints.size - 1) {
                midMidPoints.add(Point((midPoints[i].x + midPoints[i + 1].x) / 2, (midPoints[i].y + midPoints[i + 1].y) / 2))

            }

            for (i in points.indices) {
                if (i == 0 || i == points.size - 1) {
                    continue
                } else {
                    val before = Point()
                    val after = Point()
                    before.x = points[i].x - midMidPoints[i - 1].x + midPoints[i - 1].x
                    before.y = points[i].y - midMidPoints[i - 1].y + midPoints[i - 1].y
                    after.x = points[i].x - midMidPoints[i - 1].x + midPoints[i].x
                    after.y = points[i].y - midMidPoints[i - 1].y + midPoints[i].y
                    controlPoints.add(before)
                    controlPoints.add(after)
                }
            }
        }

        /**
         * 绘制两点之间的贝塞尔曲线
         */
        fun drawBezier(canvas: Canvas) {
            path.reset()
            for (i in points.indices) {
                path.reset()
                if (i == 0) {// 第一条为二阶贝塞尔
                    path.moveTo(points[i].x.toFloat(), points[i].y.toFloat())// 起点
                    path.quadTo(controlPoints[i].x.toFloat(), controlPoints[i].y.toFloat(), // 控制点
                            points[i + 1].x.toFloat(), points[i + 1].y.toFloat())
                    canvas.drawPath(path, linePaint)
                } else if (i < points.size - 2) {// 三阶贝塞尔
                    path.moveTo(points[i].x.toFloat(), points[i].y.toFloat())
                    path.cubicTo(controlPoints[2 * i - 1].x.toFloat(), controlPoints[2 * i - 1].y.toFloat(), // 控制点
                            controlPoints[2 * i].x.toFloat(), controlPoints[2 * i].y.toFloat(), // 控制点
                            points[i + 1].x.toFloat(), points[i + 1].y.toFloat())// 终点
                    canvas.drawPath(path, linePaint)
                } else if (i == points.size - 2) {// 最后一条为二阶贝塞尔
                    path.moveTo(points[i].x.toFloat(), points[i].y.toFloat())// 起点
                    path.quadTo(controlPoints[controlPoints.size - 1].x.toFloat(), controlPoints[controlPoints.size - 1].y.toFloat(), points[i + 1].x.toFloat(), points[i + 1].y.toFloat())// 终点
                    canvas.drawPath(path, linePaint)
                }
            }
        }

        /**
         * 绘制数据点
         */
        fun drawPoint(canvas: Canvas) {
            path.reset()
            for (i in points.indices) {
                pointPaint.style = Paint.Style.STROKE
                pointPaint.color = Color.BLACK
                canvas.drawCircle(points[i].x.toFloat(), points[i].y.toFloat(), 8f, pointPaint)//实心圆点
                pointPaint.style = Paint.Style.FILL
                pointPaint.color = Color.WHITE
                canvas.drawCircle(points[i].x.toFloat(), points[i].y.toFloat(), 6f, pointPaint)//实心圆点
            }
        }
        xLength = mHeight - 2 * mPadding
        mData?.let {
            var max = it.maxBy { it.num }?.num?.toInt() ?: 0
            var min = it.minBy { it.num }?.num?.toInt() ?: 0
            if (max == min) {
                degreeCount = 30
            } else {
                degreeCount = ((max - min) * 5) / 3
            }
            start = min - (degreeCount - (max - min)) / 2
            perDegree = xLength / degreeCount
            initPoint(it)
            drawBezier(canvas)
            drawPoint(canvas)
        }
    }

}
